//@author A0100617W
#include "DateParser.h"


DateParser::DateParser()
{
}


DateParser::~DateParser(void)
{
}

//@author A0100617W
//e.g. "!.play.," -> "play"
std::string DateParser::clear_Space_Punctuation(std::string s){
	size_t pos1 = s.find_first_not_of(NOT_FOUND_STRING_2);
	size_t pos2 = s.find_last_not_of(NOT_FOUND_STRING_2);

	if(pos1 == std::string::npos){
		return QUOTE_DATE;
	}

	return s.substr(pos1, pos2-pos1+1);
}






//@author A0100617W
// e.g.  Monday -> 1  Friday -> 5
int DateParser::weekdayToNum(std::string dayS){
	if(dayS[0]=='M'||dayS[0]=='m'){
		return 1;
	}else if(dayS[0]=='W'||dayS[0]=='w'){
		return 3;
	}else if(dayS[0]=='F'||dayS[0]=='f'){
		return 5;
	}else if(dayS[0]=='T'||dayS[0]=='t'){
		if(dayS[1]=='U'||dayS[1]=='u'){
			return 2;
		}else{
			return 4;
		}
	}else if(dayS[0]=='S'||dayS[0]=='s'){
		if(dayS[1]=='a'||dayS[1]=='A'){
			return 6;
		}else{
			return 7;
		}
	}

}

//@author A0100617W
bool DateParser::isLeapyear(int year){
	if(((year%4 == 0)&&(year%100 != 0))||(year%400 == 0)){
		return true;
	}else{
		return false;
	}
}


// e.g. 31/4/2014 -> 1/5/2014  (April has 30 days only)
std::string DateParser::correctDate(std::string input){
	std::istringstream in(input);
	int dd;
	int mm;
	int yy;
	int D;

	char c;

	in >> dd >> c >> mm >> c >> yy;

	if(mm == 1||mm ==3||mm ==5||mm ==7||mm ==8||mm ==10||mm ==12){
		D = 31;
	}else if(mm == 4||mm ==6||mm ==9||mm ==11){
		D = 30;
	}else{
		if(isLeapyear(yy)){
			D = 29;
		}else{
			D = 28;
		}
	}

	if(dd > D){
		dd = dd - D;
		mm++;
	}

	if(mm >12){
		mm = mm -12;
		yy++;
	}

	std::ostringstream out;

	out << (dd<10 ? ZERO_STRING_DATEPARSER: QUOTE_DATE) << dd << MINOR_DATEPARSER << (mm<10 ? ZERO_STRING_DATEPARSER: QUOTE_DATE) << mm << MINOR_DATEPARSER << yy;
	return out.str();
}




//@author A0100617W
std::string DateParser::getStandardDateString_mm_dd(std::string input){
	//format: May 5
	std::string date;
	std::istringstream in(input);
	std::ostringstream out;

	int day;
	std::string month_day;
	std::string month;
	char c;

	getline(in, month_day);

	size_t num = month_day.find_first_of(NUMBER_STRING_DATEPARSER);
	month = month_day.substr(0, num-1-0);
	std::istringstream numIn(month_day.substr(num, month_day.size()-num));
	numIn >> day;

	if(month[0]=='J'||month[0]=='j'){
		if(month[1]=='a'){
			month=ZERO_ONE_DATEPARSER;
		}else if(month[2]=='n'){
			month=ZERO_SIX_DATEPARSER;
		}else{
			month=ZERO_SEVEN_DATEPARSER;
		}
	}
	else if(month[0]=='F'||month[0]=='f'){
		month=ZERO_TWO_DATEPARSER;
	}
	else if(month[0]=='M'||month[0]=='m'){
		if(month[2]=='r'){
			month=ZERO_THREE_DATEPARSER;
		}else if(month[2]=='y'){
			month=ZERO_FIVE_DATEPARSER;
		}
	}
	else if(month[0]=='A'||month[0]=='a'){
		if(month[1]=='p'){
			month=ZERO_FOUR_DATEPARSER;
		}else if(month[2]=='u'){
			month=ZERO_EIGHT_DATEPARSER;
		}
	}
	else if(month[0]=='S'||month[0]=='s'){
		month=ZERO_NINE_DATEPARSER;
	}
	else if(month[0]=='O'||month[0]=='o'){
		month=TEN_DATEPARSER;
	}
	else if(month[0]=='N'||month[0]=='n'){
		month=ELEVEN_DATEPARSER;
	}
	else if(month[0]=='D'||month[0]=='d'){
		month=TWELVE_DATEPARSER;
	}

	CurrentTime CT;
	CT.catchCurrentDT();

	if(day < 10){
		out << ZERO_STRING_DATEPARSER << day << MINOR_DATEPARSER << month <<MINOR_DATEPARSER << CT.year;
	}else{
		out << day << MINOR_DATEPARSER << month << MINOR_DATEPARSER<< CT.year;
	}

	date = out.str();
	return date;
}


//@author A0100617W
std::string DateParser::getStandardDateString_dd_mm_yyyy(std::string input){
	//format: 3/3/2014
	std::string date;
	std::ostringstream out;

	int day;
	int month;
	int year;
	char c;

	std::istringstream ind(input);
	ind >> day;
	input = input.substr(input.find_first_not_of(NUMBER_STRING_DATEPARSER), input.size() - input.find_first_not_of(NUMBER_STRING_DATEPARSER));
	input = input.substr(1,input.size()-1);
	std::istringstream inm(input);
	inm >> month;
	input = input.substr(input.find_first_not_of(NUMBER_STRING_DATEPARSER), input.size() - input.find_first_not_of(NUMBER_STRING_DATEPARSER));
	input = input.substr(1,input.size()-1);
	std::istringstream iny(input);
	iny >> year;


	std::string dayS = std::to_string(day);
	std::string monthS = std::to_string(month);
	std::string yearS = std::to_string(year);

	if(dayS.size() <= 1){
		dayS = ZERO_STRING_DATEPARSER + dayS;
	}

	if(monthS.size() <= 1){
		monthS = ZERO_STRING_DATEPARSER + monthS;
	}


	out << dayS << MINOR_DATEPARSER << monthS << MINOR_DATEPARSER << yearS;

	date = out.str();

	return date;
}


//@author A0100617W
std::string DateParser::getStandardDateString_dd_mm_yy(std::string input){
	//format: 3/3/14
	std::string date;
	std::istringstream in(input);
	std::ostringstream out;

	int day;
	int month;
	int year;
	char c;

	std::istringstream ind(input);
	ind >> day;
	input = input.substr(input.find_first_not_of(NUMBER_STRING_DATEPARSER), input.size() - input.find_first_not_of(NUMBER_STRING_DATEPARSER));
	input = input.substr(1,input.size()-1);
	std::istringstream inm(input);
	inm >> month;
	input = input.substr(input.find_first_not_of(NUMBER_STRING_DATEPARSER), input.size() - input.find_first_not_of(NUMBER_STRING_DATEPARSER));
	input = input.substr(1,input.size()-1);
	std::istringstream iny(input);
	iny >> year;


	std::string dayS = std::to_string(day);
	std::string monthS = std::to_string(month);
	std::string yearS = std::to_string(year);

	if(dayS.size() <= 1){
		dayS = ZERO_STRING_DATEPARSER + dayS;
	}

	if(monthS.size() <= 1){
		monthS = ZERO_STRING_DATEPARSER + monthS;
	}


	if(yearS.size() == 1){
		yearS = ZERO_STRING_DATEPARSER + yearS;
	}

	yearS = TWENTY_DATEPARSER + yearS;


	out << dayS << MINOR_DATEPARSER << monthS << MINOR_DATEPARSER << yearS;

	date = out.str();

	return date;
}

//@author A0100617W
std::string DateParser::getStandardDateString_dd_mm(std::string input){
	//format: 4/6
	std::string date;
	std::istringstream in(input);
	std::ostringstream out;

	int day;
	std::string month;
	char c;

	size_t pos_space = input.find_first_of(' ');
	if(pos_space == std::string::npos){
		in >> day >> c >> month;
	}else{
		in >> day >> month;
	}

	if(month.size() <= 1){
		month = ZERO_STRING_DATEPARSER + month;
	}

	if(month[0]=='J'||month[0]=='j'){
		if(month[1]=='a'){
			month=ZERO_ONE_DATEPARSER;
		}else if(month[2]=='n'){
			month=ZERO_SIX_DATEPARSER;
		}else{
			month=ZERO_SEVEN_DATEPARSER;
		}
	}
	else if(month[0]=='F'||month[0]=='f'){
		month=ZERO_TWO_DATEPARSER;
	}
	else if(month[0]=='M'||month[0]=='m'){
		if(month[2]=='r'){
			month=ZERO_THREE_DATEPARSER;
		}else if(month[2]=='y'){
			month=ZERO_FIVE_DATEPARSER;
		}
	}
	else if(month[0]=='A'||month[0]=='a'){
		if(month[1]=='p'){
			month=ZERO_FOUR_DATEPARSER;
		}else if(month[2]=='u'){
			month=ZERO_EIGHT_DATEPARSER;
		}
	}
	else if(month[0]=='S'||month[0]=='s'){
		month=ZERO_NINE_DATEPARSER;
	}
	else if(month[0]=='O'||month[0]=='o'){
		month=TEN_DATEPARSER;
	}
	else if(month[0]=='N'||month[0]=='n'){
		month=ELEVEN_DATEPARSER;
	}
	else if(month[0]=='D'||month[0]=='d'){
		month=TWELVE_DATEPARSER;
	}

	CurrentTime CT;
	CT.catchCurrentDT();

	if(day < 10){
		out << ZERO_STRING_DATEPARSER << day << MINOR_DATEPARSER << month << MINOR_DATEPARSER << CT.year;
	}else{
		out << day << MINOR_DATEPARSER << month << MINOR_DATEPARSER << CT.year;
	}

	date = out.str();

	return date;

}

//@author A0100617W
std::string DateParser::getStandardDateString_next_weekday(std::string input){
	//format: next Mon
	std::string date;
	std::istringstream in(input);
	std::ostringstream out;

	std::string wdayS;
	getline(in, wdayS);
	wdayS = wdayS.substr(4, wdayS.size()-4);   //assert, first 4 chars are 'next'
	wdayS = wdayS.substr(wdayS.find_first_not_of(" "), wdayS.size()-wdayS.find_first_not_of(" "));

	int wday = weekdayToNum(wdayS);


	CurrentTime CT;
	CT.catchCurrentDT();

	int currentDay = weekdayToNum(CT.day_of_week);

	wday = wday + 7;

	int day = std::stoi(CT.day) + wday - currentDay;
	std::string dayS = std::to_string(day);

	if(dayS.size() <= 1){
		dayS = ZERO_STRING_DATEPARSER + dayS;
	}

	out << dayS << MINOR_DATEPARSER << CT.month <<MINOR_DATEPARSER << CT.year;
	date = out.str();
	date = correctDate(date);

	return date;

}

//@author A0100617W
std::string DateParser::getStandardDateString_weekday(std::string input){
	//format: Monday
	std::string date;
	std::istringstream in(input);
	std::ostringstream out;


	std::string wdayS;
	in >> wdayS;

	int wday = weekdayToNum(wdayS);


	CurrentTime CT;
	CT.catchCurrentDT();

	int currentDay = weekdayToNum(CT.day_of_week);

	if(wday < currentDay){
		wday = wday + 7;
	}

	int day = std::stoi(CT.day) + wday - currentDay;
	std::string dayS = std::to_string(day);


	if(dayS.size() <= 1){
		dayS = ZERO_STRING_DATEPARSER + dayS;
	}

	out << dayS << MINOR_DATEPARSER << CT.month << MINOR_DATEPARSER << CT.year;
	date = out.str();
	date = correctDate(date);		

	return date;
}

//@author A0100617W
std::string DateParser::getStandardDateString_tmr(){
	//format: tmr
	std::string date;
	std::ostringstream out;

	CurrentTime CT;
	CT.catchCurrentDT();
	int day = std::stoi(CT.day);
	day++;

	out << day << MINOR_DATEPARSER << CT.month << MINOR_DATEPARSER << CT.year;
	date = out.str();
	date = correctDate(date);

	return date;	


}

//@author A0100617W
std::string DateParser::getStandardDateString_today(){
	//format: today
	std::string date;

	CurrentTime CT;
	CT.catchCurrentDT();

	date = CT.getCurrentDate();
	date = correctDate(date);



	return date;
}




//@author A0100617W
//catch the first match of input string that matches to a date format. 
//Get the start and end positions('stPos', 'edPos') of the match in input string and the standardized date string('date').
//a date format can be:  mm(word) dd, dd mm yy, dd mm, next monday, monday, today
bool DateParser::parse(std::string input, std::string& date, size_t& stPos, size_t& edPos){

	std::smatch match;
	std::ostringstream out;


	if(std::regex_search(input, match, mmdd)){
		//format:    mm(word) dd

		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_mm_dd(rawDate);        
		return true;




	}else if(std::regex_search(input, match, ddmmyyyy)){
		//format:   dd mm yyyy
		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_dd_mm_yyyy(rawDate);
		return true;


	}else if(std::regex_search(input, match, ddmmyy)){
		//format:   dd mm yy
		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_dd_mm_yy(rawDate);

		return true;



	}else if(std::regex_search(input, match, ddmm)){
		//format:   dd mm

		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_dd_mm(rawDate);
		return true;

	}else if(std::regex_search(input, match, nextWeekday)){                // below havvvvvvvvvvvvvvvvvvvvvvnt checccccccccccccccccccccccccccccccccck the space
		//format:  next Monday

		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_next_weekday(rawDate);
		return true;

	}else if(std::regex_search(input, match, weekday)){
		//format:   Monday

		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_weekday(rawDate);


		return true;

	}else if(std::regex_search(input, match, tmr)){
		//format:  tmr

		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_tmr();

		return true;

	}else if(std::regex_search(input, match, today)){
		//format: today

		stPos = match.position();
		edPos = match.position() + match.length() - 1;
		std::string rawDate = match.str();
		date = getStandardDateString_today();

		return true;
	}

	return false;
}






